home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
listings
/
v_11_03
/
1103028a
< prev
next >
Wrap
Text File
|
1992-11-14
|
21KB
|
948 lines
/****************************************************/
/* */
/* SSX.C - stack swap executive */
/* */
/* By Tom Green and Dennis Cronin */
/* 10/19/92 */
/* */
/****************************************************/
/* turn on inline asm */
#pragma inline
#include <alloc.h>
#include <dos.h>
#include <string.h>
#include <setjmp.h>
#include "ssx.h"
#include "ssx_conf.h"
/* Task Control Block */
typedef struct tcb {
/* task chain forward ptr */
struct tcb *forw;
/* task chain backward ptr */
struct tcb *back;
/* delay chain forward ptr */
struct tcb *dforw;
/* delay chain backward ptr */
struct tcb *dback;
/* pointer to task code */
fptr task_ptr;
/* pointer to start of allocated stack */
unsigned int *stack;
/* task's current stack pointer */
unsigned int *stack_ptr;
/* delay counter */
long timeout;
/* flag for task timed out */
unsigned char timedout;
/* flag for TCB in use */
unsigned char active;
/* status flags */
unsigned char status;
/* task priority */
unsigned char priority;
/* task ID */
unsigned char id;
/* for storing extra task context */
char context[CNTXT_SZ];
} tcb;
/* misc. defines */
#define TRUE 1
#define FALSE 0
/* background task defines */
#define BG_TASK_ID 0xff
#define BG_TASK_PRI 0xff
/* make data and code local to this file */
#define LOCAL static
/* flags for the TCB status word */
#define T_READY 0 /* ready to run */
#define T_WAITING 1 /* waiting on wait_q */
#define T_DELAYED 2 /* delay timer running */
/* local function prototypes */
LOCAL tcb *get_tcb(void);
LOCAL void free_tcb(tcb *tbp);
LOCAL void put_ready(tcb *tbp);
LOCAL void rotate_tasks(tcb *tbp);
LOCAL void put_delay(long timeout);
LOCAL void run_new_task(void);
LOCAL void bg_task(void);
LOCAL void stack_swap(unsigned int **old_stack_ptr,
unsigned int **new_stack_ptr);
LOCAL int disable_ints(void);
/* local variables */
LOCAL long sys_time; /* system timer */
LOCAL unsigned char slice_cnt;
LOCAL int running;
LOCAL int initd;
LOCAL jmp_buf jbuf;
LOCAL int switch_lock;
/* task control */
LOCAL tcb t_pool[MAX_TASKS + 1]; /* pool of TCBs */
LOCAL tcb t_ready; /* head of ready task queue */
LOCAL tcb t_null; /* the NULL task */
LOCAL tcb *t_free; /* head of free queue */
LOCAL tcb *t_current; /* pointer to current task */
/* delay control */
LOCAL tcb d_chain; /* q head for delayed tasks */
/* MACROS to unlink from task and delay queues */
/* t_unlink - must be used w/ interrupts off */
#define t_unlink(tbp) \
{ \
(tbp)->back->forw = (tbp)->forw; \
if((tbp)->forw != NULL) \
(tbp)->forw->back = (tbp)->back; \
}
/* d_unlink - must be used w/ interrupts off */
#define d_unlink(tbp) \
{ \
(tbp)->dback->dforw = (tbp)->dforw; \
if((tbp)->dforw != NULL) \
(tbp)->dforw->dback = (tbp)->dback; \
}
/*
* ssx_init - init ssx data
*/
int
ssx_init(void)
{
int i;
tcb *tcbp;
if(initd)
return(INIT_ERROR);
memset(&d_chain,0,sizeof(d_chain));
/* init TCB free queue links */
for(i=0,tcbp=t_pool;i < MAX_TASKS-1;i++,tcbp++){
tcbp->forw = &t_pool[i+1];
}
t_pool[i].forw = NULL;
for(i = 0;i < MAX_TASKS;i++){
t_pool[i].active=FALSE;
}
t_current = NULL;
t_free = t_pool;
t_ready.forw = NULL;
switch_lock = 0;
/* set up background task */
if((ssx_task_create(BG_TASK_PRI,BG_TASK_ID,
bg_task,0x200,"bg_task"))
!= SUCCESS)
return(INIT_ERROR);
initd = TRUE;
return(SUCCESS);
}
/*
* sx_run - this starts executive
*/
void
ssx_run(void)
{
int val;
val = setjmp(jbuf);
if(val != 0)
return;
slice_cnt = 0;
sys_time = 0;
/* make current task ptr point to dummy tcb so
* beginning of time stack pointer save will
* have a safe place to save to.
*/
t_current = &t_null;
/* mark SSX as active */
running = TRUE;
/* this will start the first task rolling */
ssx_switch();
}
/*
* sx_stop - this stops executive
*/
void
ssx_stop(void)
{
int i;
int_state_var istate;
ints_off(istate);
/* free any allocated stacks */
for(i = 0; i < MAX_TASKS; i++){
if(t_pool[i].stack != NULL){
free(t_pool[i].stack);
t_pool[i].stack = NULL;
}
}
initd = FALSE;
running = FALSE;
restore_ints(istate);
longjmp(jbuf,1);
}
/*
* ssx_task_create - create task and set up tcb
*/
int
ssx_task_create(unsigned char task_pri,
unsigned char task_id,fptr task_ptr,
unsigned int stack_size,char *name)
{
unsigned int i;
tcb *tbp;
int_state_var istate;
ints_off(istate);
if(task_id == 0) {
restore_ints(istate);
return(TID_ERR);
}
/* check for TID already in use */
for(i = 0,tbp = t_pool;i < MAX_TASKS;i++,tbp++) {
if(tbp->active && tbp->id == task_id) {
restore_ints(istate);
return(TID_ERR);
}
}
if((tbp = get_tcb()) == NULL) { /* get a tcb */
restore_ints(istate);
return(TCB_ERR);
}
/* allocate stack for this task */
if((tbp->stack = (unsigned int *)
malloc(stack_size)) == NULL){
restore_ints(istate);
return(STACK_ERR);
}
/* fill in the blanks */
strncpy(tbp->context,name,CNTXT_SZ);
tbp->priority = task_pri;
tbp->id = task_id;
tbp->status = T_READY;
tbp->timedout = FALSE;
tbp->timeout = 0L;
tbp->forw = tbp->back =
tbp->dforw = tbp->dback = NULL;
tbp->task_ptr = task_ptr;
tbp->stack_ptr = (unsigned int *)(tbp->stack +
(stack_size / 2));
/* setup task stack to have address of start up
* routine and fake di, si, bp registers to pop.
* This part is not portable. the stack looks
* like this:
*
* |-------------------------| high
* |address of run_new_task |
* |-------------------------|
* |bp |
* |-------------------------|
* |si |
* |-------------------------|
* |di |
* |-------------------------| low
*
*/
*(--tbp->stack_ptr) = (unsigned int)run_new_task;
*(--tbp->stack_ptr) = 0; /* fake BP,SI,DI */
*(--tbp->stack_ptr) = 0; /* on stack */
*(--tbp->stack_ptr) = 0;
/* put on active chain */
rotate_tasks(tbp);
ssx_switch();
restore_ints(istate);
return(SUCCESS);
}
/*
* ssx_task_delay - cause task to delay for number
* of ticks
*/
void
ssx_task_delay(long timeout)
{
int_state_var istate;
ints_off(istate);
if(timeout == 0) {
ssx_switch();
restore_ints(istate);
return;
}
put_delay(timeout); /* put current task on */
/* delay queue */
t_unlink(t_current); /* take off ready queue */
ssx_switch();
restore_ints(istate);
}
/*
* ssx_task_delete - delete a task and remove from
* queues
*/
int
ssx_task_delete(unsigned char tas